
#include "stdafx.h"
#include "vol_user_app_info.h"
#include "vol_gif_loader.h"

typedef struct
{
	BYTE bit;
	WORD previouscode;
	WORD nextcode;
} GIFTABLE;

CVolGifLoader::CVolGifLoader()
{
	m_nDrawWay = PD_NORMAL;
	m_bGlass = TRUE;
	m_clrBackColor = RGB(255,255,255);

	m_iWidth = m_iHeight = 0;
	m_iTop = m_iLeft = 0;
	m_iTransparentIndex = 0;
	m_iTotalReadByte = 0;
	m_TransparentColor = RGB(255,255,255);
	m_iGifWidth = m_iGifHeight = 0;
	
	m_pcGlobalColorTable=0;
	m_pcGif=0;
	m_iGifSize=0;
	m_iGlobalColorSize=0;
	m_bTransparentIndex=FALSE;
	m_iDelayTime=0;
	flag=0;
	m_blOnlyOnePic = FALSE;
}

CVolGifLoader::~CVolGifLoader()
{
    if(m_pcGlobalColorTable!=NULL)delete[] m_pcGlobalColorTable;
    if(m_pcGif!=NULL)delete[] m_pcGif;
}

BOOL CVolGifLoader::load(LPBYTE p, INT nSize)
{
	if(m_pcGlobalColorTable!=NULL)delete[] m_pcGlobalColorTable;
	if(m_pcGif!=NULL)delete[] m_pcGif;
	m_pcGlobalColorTable=m_pcGif=0;
	m_iTotalReadByte=0;
	m_iGifSize=m_iGlobalColorSize=0;
	
	if (nSize <= 13 || (p[0] != 'G') || (p[1] != 'I') || (p[2] != 'F') ||
			(p[3] != '8') || ((p[4] != '7') && (p[4] != '9')) || (p[5] != 'a'))
		return FALSE;
	m_iGifWidth=*(WORD*)(p+6);
	m_iGifHeight=*(WORD*)(p+8);
	m_iBackgroundColor=p[11];
	if(p[10]&0x80)
	{
		m_iGlobalColorSize=0x01<<((p[10]&0x07)+1);
		m_pcGlobalColorTable=new BYTE[3*m_iGlobalColorSize];

		if (nSize <= 13 + 3 * m_iGlobalColorSize)
		{
			delete[] m_pcGlobalColorTable;
			m_pcGlobalColorTable=0;
			m_iGlobalColorSize=0;
			return FALSE;
		}

		::CopyMemory (m_pcGlobalColorTable, p + 13, 3 * m_iGlobalColorSize);
		p += 13 + 3 * m_iGlobalColorSize;
	}
	else
		p += 13;

	m_iGifSize=nSize-3*m_iGlobalColorSize-13;
	m_pcGifTrack=m_pcGif=new BYTE[m_iGifSize];
	::CopyMemory (m_pcGif, p, m_iGifSize);
	m_blOnlyOnePic = FALSE;

    m_blOnlyOnePic = m_iTotalReadByte>=m_iGifSize-1;
	if (m_blOnlyOnePic == FALSE)
	{
		m_pcGifTrack=m_pcGif;
		m_iTotalReadByte=0;
	}

	return TRUE;
}

HBITMAP CVolGifLoader::TakeIt (HDC hDC)
{
    ASSERT (hDC != NULL);

	UINT uLocalColorTableSize;
	WORD code,oldcode,code1;
	int iFinishCode,iResetCode;
	int iPrimaryTableSize,iTableSize;
	BITMAPINFOHEADER *bitmapheader;
	BYTE *pcColorTable;
	BYTE *pcInfo;
	GIFTABLE *pcGifTable;
	HBITMAP hBitmap;
	m_iLeft=*(WORD*)m_pcGifTrack;
	m_pcGifTrack+=2;
	m_iTop=*(WORD*)m_pcGifTrack;
	m_pcGifTrack+=2;
	m_iWidth=*(WORD*)m_pcGifTrack;
	m_pcGifTrack+=2;
	m_iWidth1=((m_iWidth-1)|0x3)+1;
	m_iHeight=*(WORD*)m_pcGifTrack;
	m_pcGifTrack+=2;
	m_cPackedField=*m_pcGifTrack++;
	m_iTotalReadByte+=9;
	m_iMaxByte=m_iWidth1*m_iHeight;
	pcInfo = new BYTE [256 * sizeof (RGBQUAD) + sizeof (BITMAPINFOHEADER) +
			m_iMaxByte + sizeof (GIFTABLE) * 4096];
	//1-BITMAPINFOHEADER
	//2-COLORTABLE
	//3-Bitmap bits
	//4-GIFTABLE;
	bitmapheader=(BITMAPINFOHEADER*)pcInfo;
	pcColorTable=pcInfo+sizeof(BITMAPINFOHEADER);
	BYTE* pcBitmap=pcColorTable+256*sizeof(RGBQUAD);
	pcGifTable=(GIFTABLE*)(pcBitmap+m_iMaxByte);
	for(int i=0;i<4096;i++)pcGifTable[i].previouscode=pcGifTable[i].nextcode=0;
	bitmapheader->biSize=sizeof(BITMAPINFOHEADER);
	bitmapheader->biWidth=m_iWidth;
	bitmapheader->biHeight=-m_iHeight;
	bitmapheader->biPlanes=1;
	bitmapheader->biBitCount=8;
	bitmapheader->biCompression=BI_RGB;
	bitmapheader->biSizeImage=0;
	bitmapheader->biXPelsPerMeter=0;
	bitmapheader->biYPelsPerMeter=0;
	bitmapheader->biClrUsed=256;
	bitmapheader->biClrImportant=256;

	if(m_cPackedField&0x80)
	{
		uLocalColorTableSize=1;
		uLocalColorTableSize<<=(m_cPackedField&7)+1;
		if(m_bTransparentIndex)
		{
			m_TransparentColor=RGB(m_pcGifTrack[m_iTransparentIndex*3],m_pcGifTrack[m_iTransparentIndex*3+1],m_pcGifTrack[m_iTransparentIndex*3+2]);
		}
		m_iTotalReadByte+=uLocalColorTableSize*3;
		for(UINT i=0;i<uLocalColorTableSize;i++)
		{
			pcColorTable[2]=*m_pcGifTrack++;
			pcColorTable[1]=*m_pcGifTrack++;
			pcColorTable[0]=*m_pcGifTrack++;
			pcColorTable[3]=0;
			pcColorTable+=4;
		}
	}
	else 
	{
		BYTE *pcGlobalColor=m_pcGlobalColorTable;
		if(m_bTransparentIndex)
		{
			m_TransparentColor=RGB(pcGlobalColor[m_iTransparentIndex*3],pcGlobalColor[m_iTransparentIndex*3+1],pcGlobalColor[m_iTransparentIndex*3+2]);
		}
		for(int i=0;i<m_iGlobalColorSize;i++)
		{
			pcColorTable[2]=*pcGlobalColor++;
			pcColorTable[1]=*pcGlobalColor++;
			pcColorTable[0]=*pcGlobalColor++;
			pcColorTable[3]=0;
			pcColorTable+=4;
		}
	}
	m_uPrimaryBitSize=m_uBitSize=(*m_pcGifTrack++);
	m_iTotalReadByte++;
	iPrimaryTableSize=iTableSize=(1<<m_uBitSize)+2;
	iFinishCode=iTableSize-1;
	iResetCode=iFinishCode-1;

	m_uPrimaryBitSize++;
	m_uBitSize++;
	m_uRemain=0;
	m_cCurentByte=0;
	m_uBlockSize=0;
	m_uReadByte=1;
	m_x=m_y=0;
	m_iPass=1;m_iRow=0;
	while((code=GetCode())!=iFinishCode)
	{
		if(code==iResetCode)
		{
			m_uBitSize=m_uPrimaryBitSize;
			iTableSize=iPrimaryTableSize;
			oldcode=GetCode();
			if(oldcode>iTableSize){delete[] pcInfo;return 0;}
			Output((BYTE)oldcode, pcBitmap);
			continue;
		}
		if(code<iTableSize) //<code> exist in the string pcGifTable
		{
			code1=code;
			WORD code2=0;
			while(code1>=iPrimaryTableSize)
			{
				pcGifTable[code1].nextcode=code2;
				code2=code1;
				code1=pcGifTable[code1].previouscode;
				if(code1>=code2)
				{
					delete[] pcInfo;
					return 0;
				}
			}
			Output((BYTE)code1, pcBitmap);
			while(code2!=0)
			{
				Output(pcGifTable[code2].bit, pcBitmap);
				code2=pcGifTable[code2].nextcode;
			}
			pcGifTable[iTableSize].bit=(BYTE)code1;
			pcGifTable[iTableSize].previouscode=oldcode;
			iTableSize++;
			if(iTableSize==(0x0001<<m_uBitSize))m_uBitSize++;
			if(m_uBitSize>12)m_uBitSize=12;
			oldcode=code;
		} 
		else    //<code> doesn't exist in the string pcGifTable
		{
			code1=oldcode;
			WORD code2=0;
			while(code1>=iPrimaryTableSize)
			{
				pcGifTable[code1].nextcode=code2;
				code2=code1;
				code1=pcGifTable[code1].previouscode;
				if(code1>=code2)
				{
					delete[] pcInfo;
					return 0;
				}
			}
			Output((BYTE)code1, pcBitmap);
			while(code2!=0)
			{
				Output(pcGifTable[code2].bit, pcBitmap);
				code2=pcGifTable[code2].nextcode;
			}
			Output((BYTE)code1, pcBitmap);
			pcGifTable[iTableSize].bit=(BYTE)code1;
			pcGifTable[iTableSize].previouscode=oldcode;
			iTableSize++;
			if(iTableSize==(0x0001<<m_uBitSize))m_uBitSize++;
			if(m_uBitSize>12)m_uBitSize=12;
			oldcode=code;
		}
	}

	hBitmap = CreateDIBitmap (hDC, bitmapheader, CBM_INIT,
			pcBitmap, (BITMAPINFO*)pcInfo, DIB_RGB_COLORS);

	m_pcGifTrack++;
	m_iTotalReadByte++;
	delete[] pcInfo;

	return hBitmap;
}

void CVolGifLoader::Output(BYTE bit, BYTE* pcBitmap)
{
	int tmp;
	if(m_cPackedField&0x40)
	{
		if(m_x==m_iWidth)
		{
			m_x=0;
			if(m_iPass==1)m_iRow+=8;
			if(m_iPass==2)m_iRow+=8;
			if(m_iPass==3)m_iRow+=4;
			if(m_iPass==4)m_iRow+=2;
			if(m_iRow>=m_iHeight){m_iPass+=1;m_iRow=16>>m_iPass;}
		}
		tmp=m_iRow*m_iWidth1+m_x;
		pcBitmap[tmp]=bit;
		m_x++;
	}
	else
	{
		if(m_x==m_iWidth){m_x=0;m_y++;}
		tmp=m_y*m_iWidth1+m_x;
		m_x++;
	}
	if(tmp>m_iMaxByte)return;
	pcBitmap[tmp]=bit;
}

BYTE CVolGifLoader::GetByte()
{
	if(m_uReadByte>=m_uBlockSize)
	{
		m_uBlockSize=*m_pcGifTrack++;
		m_uReadByte=0;
		m_iTotalReadByte+=m_uBlockSize+1;
		if(m_iTotalReadByte>m_iGifSize){m_iTotalReadByte-=m_uBlockSize+1;return 0xFF;}
		if(m_uBlockSize==0){m_pcGifTrack--;m_iTotalReadByte--;return 0xFF;}
	}
	m_uReadByte++;
	return *m_pcGifTrack++;
}

WORD CVolGifLoader::GetCode()
{
	UINT tmp1;
	BYTE tmp;
	tmp=1;
	if(m_uRemain>=m_uBitSize)
	{
		tmp<<=m_uBitSize;
		tmp--;
		tmp1=m_cCurentByte&tmp;
		m_cCurentByte>>=m_uBitSize;
		m_uRemain-=m_uBitSize;
	}
	else
	{
		tmp<<=m_uRemain;
		tmp--;
		tmp1=m_cCurentByte;
		m_cCurentByte=GetByte();
		tmp=1;
		if(8>=(m_uBitSize-m_uRemain))
		{
			tmp<<=(m_uBitSize-m_uRemain);
			tmp--;
			tmp1=(((UINT)(m_cCurentByte&tmp))<<m_uRemain)+tmp1;
			m_cCurentByte>>=(m_uBitSize-m_uRemain);
			m_uRemain=8-(m_uBitSize-m_uRemain);
		}
		else
		{
			tmp1=(((UINT)(m_cCurentByte))<<m_uRemain)+tmp1;
			m_cCurentByte=GetByte();
			tmp<<=m_uBitSize-m_uRemain-8;
			tmp--;
			tmp1=(((UINT)(m_cCurentByte&tmp))<<(m_uRemain+8))+tmp1;
			m_cCurentByte>>=m_uBitSize-m_uRemain-8;
			m_uRemain=8-(m_uBitSize-m_uRemain-8);
		}
	}
	return tmp1;
}
